package com.maiji.cloud.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.maiji.cloud.config.MyRedisConfig;
import com.maiji.cloud.entities.login.AppUser;
import com.maiji.cloud.entities.login.Recipe;
import com.maiji.cloud.entities.login.RecipeThumbsUpOrCollection;
import com.maiji.cloud.mapper.RecipeThumbsUpOrCollectionMapper;
import com.maiji.cloud.request.ReqMetaData;
import com.maiji.cloud.request.login.RecipeFindAllReqData;
import com.maiji.cloud.response.BaseMetaResDto;
import com.maiji.cloud.response.BaseResDto;
import com.maiji.cloud.response.ResMetaData;
import com.maiji.cloud.response.Status;
import com.maiji.cloud.response.login.RecipeResData;
import com.maiji.cloud.service.AppUserService;
import com.maiji.cloud.service.RecipeService;
import com.maiji.cloud.service.RecipeThumbsUpOrCollectionService;
import com.maiji.cloud.utils.RedisUtil;
import com.maiji.cloud.utils.UUID_MD5;
import org.apache.commons.lang.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
public class RecipeThumbsUpOrCollectionServiceImpl extends ServiceImpl<RecipeThumbsUpOrCollectionMapper, RecipeThumbsUpOrCollection>
        implements RecipeThumbsUpOrCollectionService {

    @Autowired
    private RedisTemplate<String, Object> maiji1RedisTemplate;
    @Autowired
    private AppUserService appUserService;
    @Autowired
    private RecipeService recipeService;

    @Override
    public BaseMetaResDto<List<RecipeResData>> findAllRecipeCollection(String token, ReqMetaData metaData) {
        AppUser appUser = RedisUtil.getAppUserByRedis(maiji1RedisTemplate, MyRedisConfig.REDISDATABASENO, token, appUserService);
        EntityWrapper<RecipeThumbsUpOrCollection> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("user_id", appUser.getUuId());
        entityWrapper.eq("type", 2);
        entityWrapper.eq("is_cancel", 0);
        entityWrapper.orderBy("date", false);
        Page<RecipeThumbsUpOrCollection> page = selectPage(new Page<>(metaData.getPage(), metaData.getSize()), entityWrapper);
        List<String> recipeIds = page.getRecords().parallelStream().map(RecipeThumbsUpOrCollection::getRecipeId).collect(Collectors.toList());
        RecipeFindAllReqData recipeFindAllReqData = new RecipeFindAllReqData().setRecipeIds(recipeIds);
        BaseMetaResDto<List<RecipeResData>> baseMetaResDto = recipeService.findAllRecipes(recipeFindAllReqData, token, metaData);
        Map<String, RecipeResData> recipeResDataMap = baseMetaResDto.getData().parallelStream().collect(Collectors.toMap(RecipeResData::getUuId, rrd -> rrd));
        List<RecipeResData> recipeResDataList = recipeIds.parallelStream().map(recipeId -> recipeResDataMap.get(recipeId)).collect(Collectors.toList());
        ResMetaData resMetaData = new ResMetaData(page.getCurrent(), page.getSize(), page.getTotal());
        return baseMetaResDto.setData(recipeResDataList).setResMetaData(resMetaData);
    }

    @Override
    public BaseResDto cancelCollectionRecipes(List<String> recipeIds, String token) {
        AppUser appUser = RedisUtil.getAppUserByRedis(maiji1RedisTemplate, MyRedisConfig.REDISDATABASENO, token, appUserService);
        String userId = appUser.getUuId();
        EntityWrapper<RecipeThumbsUpOrCollection> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("user_id", userId);
        if (recipeIds == null || recipeIds.size() == 0)
            recipeIds = selectList(entityWrapper).parallelStream().map(RecipeThumbsUpOrCollection::getRecipeId).collect(Collectors.toList());
        if (recipeIds.size() == 0) return new BaseResDto(Status.SUCCESS);
        entityWrapper.in("recipe_id", recipeIds);
        if (! delete(entityWrapper)) return new BaseResDto(Status.ERROR.setMessage("批量取消用户收藏食谱失败"));
        List<String> recipeCollectionRedisKeys = recipeIds.parallelStream().map(recipeId ->
                RedisUtil.getRedisKey(REDISNAMESPACE, recipeId, userId, "2")).collect(Collectors.toList());
        maiji1RedisTemplate.delete(recipeCollectionRedisKeys);
        List<Recipe> recipeList = recipeService.selectBatchIds(recipeIds)
                .parallelStream().map(recipe -> recipe.setCollectionNo(recipe.getCollectionNo() - 1)).collect(Collectors.toList());
        if (recipeService.updateBatchById(recipeList)) {
            List<String> recipeRedisKeys = recipeIds.parallelStream().map(recipeId ->
                    RedisUtil.getRedisKey(RecipeService.REDISNAMESPACE, recipeId)).collect(Collectors.toList());
            maiji1RedisTemplate.delete(recipeRedisKeys);
        }
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public BaseResDto thumbsUpRecipeById(String recipeId, Integer type, String token) {
        AppUser appUser = RedisUtil.getAppUserByRedis(maiji1RedisTemplate, MyRedisConfig.REDISDATABASENO, token, appUserService);
        String userId = appUser.getUuId();
        Recipe recipe = recipeService.selectById(recipeId);
        RecipeThumbsUpOrCollection recipeThumbsUpOrCollection = selectOneByRedis(recipeId, userId, type);
        if (recipeThumbsUpOrCollection == null) {
            recipeThumbsUpOrCollection = new RecipeThumbsUpOrCollection();
            recipeThumbsUpOrCollection.setUuId(UUID_MD5.getUUID())
                    .setRecipeId(recipeId)
                    .setUserId(userId)
                    .setType(type)
                    .setDate(new Date())
                    .setIsCancel(0);
            if (insert(recipeThumbsUpOrCollection)) {
                if (type == 1) recipe.setThumbsUpNo(recipe.getThumbsUpNo() + 1);
                if (type == 2) recipe.setCollectionNo(recipe.getCollectionNo() + 1);
            }
        } else {
            Integer isCancel = recipeThumbsUpOrCollection.getIsCancel();
            recipeThumbsUpOrCollection.setIsCancel(isCancel==1? 0: 1);
            if (updateById(recipeThumbsUpOrCollection)){
                if (type == 1) recipe.setThumbsUpNo(recipe.getThumbsUpNo() + (isCancel==1? 1: -1));
                if (type == 2) recipe.setCollectionNo(recipe.getCollectionNo() + (isCancel==1? 1: -1));
            }
        }
        if (recipeService.updateById(recipe)) {
            String redisKey = RedisUtil.getRedisKey(REDISNAMESPACE, recipeId, userId, type.toString());
            RedisUtil.setObject(maiji1RedisTemplate, redisKey, recipeThumbsUpOrCollection);
            return new BaseResDto(Status.SUCCESS);
        } else thumbsUpRecipeById(recipeId, type, token);
        return new BaseResDto(Status.ERROR);
    }
    
    @Override
    public RecipeThumbsUpOrCollection selectOneByRedis(String recipe_id, String user_id, Integer type) {
        String redisKey = RedisUtil.getRedisKey(REDISNAMESPACE, recipe_id, user_id, type.toString());
        RecipeThumbsUpOrCollection recipeThumbsUpOrCollection = (RecipeThumbsUpOrCollection) maiji1RedisTemplate.opsForValue().get(redisKey);
        if (recipeThumbsUpOrCollection == null) {
            EntityWrapper<RecipeThumbsUpOrCollection> entityWrapper = new EntityWrapper<>();
            entityWrapper.eq("recipe_id", recipe_id);
            entityWrapper.eq("user_id", user_id);
            entityWrapper.eq("type", type);
            recipeThumbsUpOrCollection = selectOne(entityWrapper);
            if (recipeThumbsUpOrCollection != null) RedisUtil.setObject(maiji1RedisTemplate, redisKey, recipeThumbsUpOrCollection);
        }
        return recipeThumbsUpOrCollection;
    }

    @Override
    public Boolean isThumbsUpOrCollection(String recipe_id, String user_id, Integer type) {
        RecipeThumbsUpOrCollection recipeThumbsUpOrCollection = selectOneByRedis(recipe_id, user_id, type);
        if (recipeThumbsUpOrCollection == null) return false;
        else return ! BooleanUtils.toBoolean(recipeThumbsUpOrCollection.getIsCancel());
    }

}
